{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DEMO of the MAAP-tiler api"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: mapboxgl in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (0.10.1)\n",
      "Requirement already satisfied: jinja2 in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from mapboxgl) (2.10)\n",
      "Requirement already satisfied: colour in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from mapboxgl) (0.1.5)\n",
      "Requirement already satisfied: geojson in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from mapboxgl) (2.4.1)\n",
      "Requirement already satisfied: chroma-py in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from mapboxgl) (0.1.0.dev1)\n",
      "Requirement already satisfied: matplotlib in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from mapboxgl) (3.0.3)\n",
      "Requirement already satisfied: MarkupSafe>=0.23 in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from jinja2->mapboxgl) (1.1.1)\n",
      "Requirement already satisfied: numpy>=1.10.0 in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from matplotlib->mapboxgl) (1.16.2)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from matplotlib->mapboxgl) (1.0.1)\n",
      "Requirement already satisfied: cycler>=0.10 in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from matplotlib->mapboxgl) (0.10.0)\n",
      "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from matplotlib->mapboxgl) (2.3.1)\n",
      "Requirement already satisfied: python-dateutil>=2.1 in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from matplotlib->mapboxgl) (2.8.0)\n",
      "Requirement already satisfied: setuptools in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from kiwisolver>=1.0.1->matplotlib->mapboxgl) (40.8.0)\n",
      "Requirement already satisfied: six in /Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages (from cycler>=0.10->matplotlib->mapboxgl) (1.12.0)\n"
     ]
    }
   ],
   "source": [
    "# Install mapboxgl-jupyter\n",
    "!pip install mapboxgl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import json\n",
    "import requests\n",
    "import urllib.parse\n",
    "\n",
    "from mapboxgl.utils import *\n",
    "from mapboxgl.viz import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "maap_endpoint = \"https://8e9mu91qr6.execute-api.us-east-1.amazonaws.com/production\"\n",
    "\n",
    "token = os.environ[\"MAPBOX_ACCESS_TOKEN\"]\n",
    "\n",
    "# LVIS COG\n",
    "LVIS_file = \"s3://cumulus-map-internal/products/AFLVIS2-CHM/LVIS2_Gabon2016_0220_R1808_038024_chm.tif\"\n",
    "\n",
    "# UAVSAR COG\n",
    "SAR_file = \"s3://cumulus-map-internal/products/plant-analysis/lopegeo_mlk_cog_001.tif\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### UAVSAR Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"address\": \"s3://cumulus-map-internal/products/plant-analysis/lopegeo_mlk_cog_001.tif\",\n",
      "    \"bounds\": {\n",
      "        \"value\": [\n",
      "            11.41071054972465,\n",
      "            -0.3848431107778577,\n",
      "            11.857202093935395,\n",
      "            0.09666737807686826\n",
      "        ],\n",
      "        \"crs\": \"EPSG:4326\"\n",
      "    },\n",
      "    \"minzoom\": 9,\n",
      "    \"maxzoom\": 13,\n",
      "    \"band_descriptions\": [\n",
      "        [\n",
      "            1,\n",
      "            \"band1\"\n",
      "        ]\n",
      "    ],\n",
      "    \"statistics\": {\n",
      "        \"1\": {\n",
      "            \"pc\": [\n",
      "                0.012231900878250598,\n",
      "                0.3714591777324676\n",
      "            ],\n",
      "            \"min\": 0.0,\n",
      "            \"max\": 18.154794692993164,\n",
      "            \"std\": 0.10814061759121658,\n",
      "            \"histogram\": [\n",
      "                [\n",
      "                    286052,\n",
      "                    247,\n",
      "                    22,\n",
      "                    11,\n",
      "                    6,\n",
      "                    0,\n",
      "                    0,\n",
      "                    2,\n",
      "                    0,\n",
      "                    0,\n",
      "                    0,\n",
      "                    0,\n",
      "                    1,\n",
      "                    0,\n",
      "                    0,\n",
      "                    0,\n",
      "                    0,\n",
      "                    0,\n",
      "                    0,\n",
      "                    1\n",
      "                ],\n",
      "                [\n",
      "                    0.0,\n",
      "                    0.9077397346496582,\n",
      "                    1.8154794692993164,\n",
      "                    2.7232192039489744,\n",
      "                    3.6309589385986327,\n",
      "                    4.538698673248291,\n",
      "                    5.446438407897949,\n",
      "                    6.354178142547608,\n",
      "                    7.2619178771972654,\n",
      "                    8.169657611846924,\n",
      "                    9.077397346496582,\n",
      "                    9.98513708114624,\n",
      "                    10.892876815795898,\n",
      "                    11.800616550445556,\n",
      "                    12.708356285095215,\n",
      "                    13.616096019744873,\n",
      "                    14.523835754394531,\n",
      "                    15.431575489044189,\n",
      "                    16.33931522369385,\n",
      "                    17.247054958343504,\n",
      "                    18.154794692993164\n",
      "                ]\n",
      "            ]\n",
      "        }\n",
      "    }\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# Fetching SAR metadata\n",
    "r = requests.get(f\"{maap_endpoint}/metadata?url={SAR_file}\")\n",
    "meta = r.json()\n",
    "\n",
    "print(json.dumps(meta, indent=4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/vincentsarago/Workspace/venv/py37/lib/python3.7/site-packages/IPython/core/display.py:689: UserWarning: Consider using IPython.display.IFrame instead\n",
      "  warnings.warn(\"Consider using IPython.display.IFrame instead\")\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<iframe id=\"map\", srcdoc=\"<!DOCTYPE html>\n",
       "<html>\n",
       "<head>\n",
       "<title>mapboxgl-jupyter viz</title>\n",
       "<meta charset='UTF-8' />\n",
       "<meta name='viewport'\n",
       "      content='initial-scale=1,maximum-scale=1,user-scalable=no' />\n",
       "<script type='text/javascript'\n",
       "        src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.js'></script>\n",
       "<link type='text/css'\n",
       "      href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css' \n",
       "      rel='stylesheet' />\n",
       "\n",
       "<style type='text/css'>\n",
       "    body { margin:0; padding:0; }\n",
       "    .map { position: absolute; top:0; bottom:0; width:100%; }\n",
       "    .legend {\n",
       "        background-color: white;\n",
       "        color: #6e6e6e;\n",
       "        border-radius: 3px;\n",
       "        bottom: 10px;\n",
       "        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.10);\n",
       "        font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n",
       "        padding: 0;\n",
       "        position: absolute;\n",
       "        right: 10px;\n",
       "        z-index: 1;\n",
       "        min-width: 100px;\n",
       "    }\n",
       "   .legend.horizontal {bottom: 10px; text-align: left;}\n",
       "\n",
       "    /* legend header */\n",
       "    .legend .legend-header { border-radius: 3px 3px 0 0; background: white; }\n",
       "    .legend .legend-title {\n",
       "        padding: 6px 12px 6px 12px;\n",
       "        text-shadow: 0 0 2px white;\n",
       "        text-transform: capitalize;\n",
       "        text-align: center;\n",
       "        font-weight: bold !important;\n",
       "        font-size: 14px;\n",
       "        font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n",
       "        max-width: 160px;\n",
       "    }\n",
       "    .legend-title {padding: 6px 12px 6px 12px; text-shadow: 0 0 2px #FFF; text-transform: capitalize; text-align: center; max-width: 160px; font-size: 0.9em; font-weight: bold;}\n",
       "    .legend.horizontal .legend-title {text-align: left;}\n",
       "\n",
       "    /* legend items */\n",
       "    .legend-content {margin: 6px 12px 6px 12px; overflow: hidden; padding: 0; float: left; list-style: none; font-size: 0.8em;}\n",
       "    .legend.vertical .legend-item {white-space: nowrap;}\n",
       "    .legend-value {display: inline-block; line-height: 18px; vertical-align: top;}\n",
       "    .legend.horizontal ul.legend-content li.legend-item .legend-value,\n",
       "    .legend.horizontal ul.legend-content li.legend-item {display: inline-block; float: left; width: 30px; margin-bottom: 0; text-align: center; height: 30px;}\n",
       "\n",
       "    /* legend key styles */\n",
       "    .legend-key {display: inline-block; height: 10px;}\n",
       "    .legend-key.default, .legend-key.square {border-radius: 0;}\n",
       "    .legend-key.circle {border-radius: 50%;}\n",
       "    .legend-key.rounded-square {border-radius: 20%;}\n",
       "    .legend.vertical .legend-key {width: 10px; margin-right: 5px; margin-left: 1px;}\n",
       "    .legend.horizontal .legend-key {width: 30px; margin-right: 0; margin-top: 1px; float: left;}\n",
       "    .legend.horizontal .legend-key.square, .legend.horizontal .legend-key.rounded-square, .legend.horizontal .legend-key.circle {margin-left: 10px; width: 10px;}\n",
       "    .legend.horizontal .legend-key.line {margin-left: 5px;}\n",
       "    .legend.horizontal .legend-key.line, .legend.vertical .legend-key.line {border-radius: 10%; width: 20px; height: 3px; margin-bottom: 2px;}\n",
       "\n",
       "    /* gradient bar alignment */\n",
       "    .gradient-bar {margin: 6px 12px 6px 12px;}\n",
       "    .legend.horizontal .gradient-bar {width: 88%; height: 10px;}\n",
       "    .legend.vertical .gradient-bar {width: 10px; min-height: 50px; position: absolute; bottom: 4px;}\n",
       "\n",
       "    /* contiguous vertical bars (discrete) */\n",
       "    .legend.vertical.contig .legend-key {height: 15px; width: 10px;}\n",
       "    .legend.vertical.contig li.legend-item {height: 15px;}\n",
       "    .legend.vertical.contig {padding-bottom: 6px;}\n",
       "\n",
       "</style>\n",
       "\n",
       "</head>\n",
       "<body>\n",
       "\n",
       "<div id='map' class='map'></div>\n",
       "\n",
       "<script type='text/javascript'>\n",
       "\n",
       "var legendHeader;\n",
       "\n",
       "function calcColorLegend(myColorStops, title) {\n",
       "\n",
       "    // create legend\n",
       "    var legend = document.createElement('div');\n",
       "    if ('square' === 'contiguous-bar') {\n",
       "        legend.className = 'legend vertical contig';\n",
       "    }\n",
       "    else {\n",
       "        legend.className = 'legend vertical';\n",
       "    }\n",
       "\n",
       "    legend.id = 'legend';\n",
       "    document.body.appendChild(legend);\n",
       "\n",
       "    // add legend header and content elements\n",
       "    var mytitle = document.createElement('div'),\n",
       "        legendContent = document.createElement('ul');\n",
       "    legendHeader = document.createElement('div');\n",
       "    mytitle.textContent = title;\n",
       "    mytitle.className = 'legend-title'\n",
       "    legendHeader.className = 'legend-header'\n",
       "    legendContent.className = 'legend-content'\n",
       "    legendHeader.appendChild(mytitle);\n",
       "    legend.appendChild(legendHeader);\n",
       "    legend.appendChild(legendContent);\n",
       "\n",
       "    if (false === true) {\n",
       "        var gradientText = 'linear-gradient(to right, ';\n",
       "        var gradient = document.createElement('div');\n",
       "        gradient.className = 'gradient-bar';\n",
       "        legend.appendChild(gradient);\n",
       "    }\n",
       "\n",
       "    // calculate a legend entries on a Mapbox GL Style Spec property function stops array\n",
       "    for (p = 0; p < myColorStops.length; p++) {\n",
       "        if (!!document.getElementById('legend-points-value-' + p)) {\n",
       "            //update the legend if it already exists\n",
       "            document.getElementById('legend-points-value-' + p).textContent = myColorStops[p][0];\n",
       "            document.getElementById('legend-points-id-' + p).style.backgroundColor = myColorStops[p][1];\n",
       "        }\n",
       "        else {\n",
       "            // create the legend if it doesn't yet exist\n",
       "            var item = document.createElement('li');\n",
       "            item.className = 'legend-item';\n",
       "\n",
       "            var key = document.createElement('span');\n",
       "            key.className = 'legend-key square';\n",
       "            key.id = 'legend-points-id-' + p;\n",
       "            key.style.backgroundColor = myColorStops[p][1];   \n",
       "\n",
       "            var value = document.createElement('span');\n",
       "            value.className = 'legend-value';\n",
       "            value.id = 'legend-points-value-' + p;\n",
       "\n",
       "            item.appendChild(key);\n",
       "            item.appendChild(value);\n",
       "            legendContent.appendChild(item);\n",
       "            \n",
       "            data = document.getElementById('legend-points-value-' + p)\n",
       "\n",
       "            // round number values in legend if precision defined\n",
       "            if ((typeof(myColorStops[p][0]) == 'number') && (typeof(null) == 'number')) {\n",
       "                data.textContent = myColorStops[p][0].toFixed(null);\n",
       "            }\n",
       "            else {\n",
       "                data.textContent = myColorStops[p][0];\n",
       "            }\n",
       "\n",
       "            // add color stop to gradient list\n",
       "            if (false === true) {\n",
       "                if (p < myColorStops.length - 1) {\n",
       "                    gradientText = gradientText + myColorStops[p][1] + ', ';\n",
       "                }\n",
       "                else {\n",
       "                    gradientText = gradientText + myColorStops[p][1] + ')';\n",
       "                }\n",
       "                if ('vertical' === 'vertical') {\n",
       "                    gradientText = gradientText.replace('to right', 'to bottom');\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "\n",
       "    if (false === true) {\n",
       "        // convert to gradient scale appearance\n",
       "        gradient.style.background = gradientText;\n",
       "\n",
       "        // hide legend keys generated above\n",
       "        var keys = document.getElementsByClassName('legend-key');\n",
       "        for (var i=0; i < keys.length; i++) {\n",
       "            keys[i].style.visibility = 'hidden';\n",
       "        }\n",
       "\n",
       "        if ('vertical' === 'vertical') {\n",
       "            gradient.style.height = (legendContent.offsetHeight - 6) + 'px';\n",
       "        }\n",
       "    }\n",
       "\n",
       "    // add class for styling bordered legend keys\n",
       "    if (true) {\n",
       "        var keys = document.getElementsByClassName('legend-key');\n",
       "        for (var i=0; i < keys.length; i++) {\n",
       "            if (keys[i]) {\n",
       "                keys[i].classList.add('bordered');\n",
       "            }\n",
       "        }\n",
       "        var gradientBars = document.getElementsByClassName('gradient-bar');\n",
       "        for (var i=0; i < keys.length; i++) {\n",
       "            if (gradientBars[i]) {\n",
       "                gradientBars[i].classList.add('bordered');\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "\n",
       "    // update right-margin for compact Mapbox attribution based on calculated legend width\n",
       "    var attribMargin = legend.offsetWidth + 15;\n",
       "    document.getElementsByClassName('mapboxgl-ctrl-attrib')[0].style.marginRight =  attribMargin.toString() + 'px';\n",
       "\n",
       "}\n",
       "\n",
       "\n",
       "function generateInterpolateExpression(propertyValue, stops) {\n",
       "    var expression;\n",
       "    if (propertyValue == 'zoom') {\n",
       "        expression = ['interpolate', ['exponential', 1.2], ['zoom']]\n",
       "    }\n",
       "    else if (propertyValue == 'heatmap-density') {\n",
       "        expression = ['interpolate', ['linear'], ['heatmap-density']]\n",
       "    }\n",
       "    else {\n",
       "        expression = ['interpolate', ['linear'], ['get', propertyValue]]\n",
       "    }\n",
       "\n",
       "    for (var i=0; i<stops.length; i++) {\n",
       "        expression.push(stops[i][0], stops[i][1])\n",
       "    }\n",
       "    return expression\n",
       "}\n",
       "\n",
       "\n",
       "function generateMatchExpression(propertyValue, stops, defaultValue) {\n",
       "    var expression;\n",
       "    expression = ['match', ['get', propertyValue]]\n",
       "    for (var i=0; i<stops.length; i++) {\n",
       "        expression.push(stops[i][0], stops[i][1])\n",
       "    }\n",
       "    expression.push(defaultValue)\n",
       "    \n",
       "    return expression\n",
       "}\n",
       "\n",
       "\n",
       "function generatePropertyExpression(expressionType, propertyValue, stops, defaultValue) {\n",
       "    var expression;\n",
       "    if (expressionType == 'match') {\n",
       "        expression = generateMatchExpression(propertyValue, stops, defaultValue)\n",
       "    }\n",
       "    else if (propertyValue == 'identity') {\n",
       "        expression = ['get', propertyValue]\n",
       "    }\n",
       "    else {\n",
       "        expression = generateInterpolateExpression(propertyValue, stops)\n",
       "    }\n",
       "\n",
       "    return expression\n",
       "}\n",
       "\n",
       "</script>\n",
       "\n",
       "<!-- main map creation code, extended by mapboxgl/templates/raster.html -->\n",
       "<script type='text/javascript'>\n",
       "\n",
       "    mapboxgl.accessToken = 'pk.eyJ1IjoidmluY2VudHNhcmFnbyIsImEiOiJjamxwa3JkaWkwZ3BjM3dudmZmazQwYjI2In0.eUzks_hqH-QVIlnXUKmKsA';\n",
       "\n",
       "    var transformRequest = function(url, resourceType) {\n",
       "        const isMapboxRequest = url.slice(8, 22) === 'api.mapbox.com' ||\n",
       "          url.slice(10, 26) === 'tiles.mapbox.com';\n",
       "      \n",
       "        return {\n",
       "          url: isMapboxRequest ? url.replace('?', '?pluginName=PythonMapboxgl&') : url\n",
       "        }\n",
       "    };\n",
       "\n",
       "    var map = new mapboxgl.Map({\n",
       "        container: 'map',\n",
       "        attributionControl: false,\n",
       "        style: 'mapbox://styles/mapbox/light-v10?optimize=true',\n",
       "        center: [11.633956321830023, -0.14408786635049473],\n",
       "        zoom: 10,\n",
       "        pitch: 0,\n",
       "        bearing: 0,\n",
       "        scrollZoom: true,\n",
       "        touchZoom: true,\n",
       "        doubleClickZoom: true,\n",
       "        boxZoom: true,\n",
       "        preserveDrawingBuffer: false,\n",
       "        transformRequest: transformRequest\n",
       "    });\n",
       "\n",
       "    \n",
       "    \n",
       "        map.addControl(new mapboxgl.AttributionControl({ compact: true }));\n",
       "\n",
       "    \n",
       "\n",
       "    \n",
       "\n",
       "        map.addControl(new mapboxgl.NavigationControl());\n",
       "\n",
       "    \n",
       "\n",
       "    \n",
       "\n",
       "    \n",
       "\n",
       "    map.on('style.load', function() {\n",
       "      console.log('Yoooooo');\n",
       "        let params = {\n",
       "            'type': 'raster',\n",
       "            'tiles': [\n",
       "                 'http://127.0.0.1:8000/tiles/{z}/{x}/{y}.png?url=s3%3A%2F%2Fcumulus-map-internal%2Fproducts%2Fplant-analysis%2Flopegeo_mlk_cog_001.tif&rescale=-1%2C1'\n",
       "            ],\n",
       "            'tileSize': 256,\n",
       "            'minzoom': 8,\n",
       "            'maxzoom': 15\n",
       "        }\n",
       "        if ([11.41071054972465, -0.3848431107778577, 11.857202093935395, 0.09666737807686826] !== undefined) params.bounds = [11.41071054972465, -0.3848431107778577, 11.857202093935395, 0.09666737807686826];\n",
       "\n",
       "        map.addSource('raster-tiles', params);\n",
       "\n",
       "        map.addLayer({\n",
       "            'id': 'raster-tiles',\n",
       "            'type': 'raster',\n",
       "            'source': 'raster-tiles'\n",
       "        }, '' );\n",
       "\n",
       "    });\n",
       "\n",
       "\n",
       "\n",
       "</script>\n",
       "\n",
       "<!-- add capability to export map or legend to image file -->\n",
       "\n",
       "\n",
       "</body>\n",
       "</html>\" style=\"width: 100%; height: 800px;\"></iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bbox = meta[\"bounds\"][\"value\"]\n",
    "lat = (bbox[3] - bbox[1]) / 2 + bbox[1]\n",
    "lng = (bbox[2] - bbox[0]) / 2 + bbox[0]\n",
    "\n",
    "query_params = dict(\n",
    "    url=SAR_file,\n",
    "    rescale=\"-1,1\",\n",
    ")\n",
    "\n",
    "#Because the data is of `float` type we need to rescale the data between 0 and 255\n",
    "# `rescale=\"-1,1\"`: tell the tiler to rescale the data from -1 and 1 to 0 and 255. \n",
    "\n",
    "qs = urllib.parse.urlencode(query_params)\n",
    "\n",
    "tiles_url = f\"{maap_endpoint}/tiles/{{z}}/{{x}}/{{y}}.png?{qs}\"\n",
    "viz = RasterTilesViz(\n",
    "    tiles_url,\n",
    "    height='800px',\n",
    "    zoom=10,\n",
    "    access_token=token,\n",
    "    tiles_size=256,\n",
    "    tiles_bounds=bbox,\n",
    "    center=(lng, lat),\n",
    "    tiles_minzoom=8,\n",
    "    tiles_maxzoom=15,\n",
    ")\n",
    "\n",
    "viz.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## LVIS Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"address\": \"s3://cumulus-map-internal/products/AFLVIS2-CHM/LVIS2_Gabon2016_0220_R1808_038024_chm.tif\",\n",
      "    \"bounds\": {\n",
      "        \"value\": [\n",
      "            9.79035,\n",
      "            -0.171108,\n",
      "            10.20635,\n",
      "            0.164892\n",
      "        ],\n",
      "        \"crs\": \"EPSG:4326\"\n",
      "    },\n",
      "    \"minzoom\": 9,\n",
      "    \"maxzoom\": 11,\n",
      "    \"band_descriptions\": [\n",
      "        [\n",
      "            1,\n",
      "            \"band1\"\n",
      "        ]\n",
      "    ],\n",
      "    \"statistics\": {\n",
      "        \"1\": {\n",
      "            \"pc\": [\n",
      "                2.314199924468994,\n",
      "                51.1171989440918\n",
      "            ],\n",
      "            \"min\": 0.0,\n",
      "            \"max\": 59.7599983215332,\n",
      "            \"std\": 13.44550518102395,\n",
      "            \"histogram\": [\n",
      "                [\n",
      "                    361,\n",
      "                    27,\n",
      "                    123,\n",
      "                    107,\n",
      "                    112,\n",
      "                    89,\n",
      "                    122,\n",
      "                    119,\n",
      "                    175,\n",
      "                    198,\n",
      "                    313,\n",
      "                    436,\n",
      "                    725,\n",
      "                    774,\n",
      "                    653,\n",
      "                    477,\n",
      "                    200,\n",
      "                    84,\n",
      "                    25,\n",
      "                    7\n",
      "                ],\n",
      "                [\n",
      "                    0.0,\n",
      "                    2.98799991607666,\n",
      "                    5.97599983215332,\n",
      "                    8.96399974822998,\n",
      "                    11.95199966430664,\n",
      "                    14.9399995803833,\n",
      "                    17.92799949645996,\n",
      "                    20.916000366210938,\n",
      "                    23.90399932861328,\n",
      "                    26.891998291015625,\n",
      "                    29.8799991607666,\n",
      "                    32.86800003051758,\n",
      "                    35.85599899291992,\n",
      "                    38.843997955322266,\n",
      "                    41.832000732421875,\n",
      "                    44.81999969482422,\n",
      "                    47.80799865722656,\n",
      "                    50.795997619628906,\n",
      "                    53.78399658203125,\n",
      "                    56.77199935913086,\n",
      "                    59.7599983215332\n",
      "                ]\n",
      "            ]\n",
      "        }\n",
      "    }\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# Fetching SAR metadata\n",
    "r = requests.get(f\"{maap_endpoint}/metadata?url={LVIS_file}\")\n",
    "meta = r.json()\n",
    "\n",
    "print(json.dumps(meta, indent=4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<iframe id=\"map\", srcdoc=\"<!DOCTYPE html>\n",
       "<html>\n",
       "<head>\n",
       "<title>mapboxgl-jupyter viz</title>\n",
       "<meta charset='UTF-8' />\n",
       "<meta name='viewport'\n",
       "      content='initial-scale=1,maximum-scale=1,user-scalable=no' />\n",
       "<script type='text/javascript'\n",
       "        src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.js'></script>\n",
       "<link type='text/css'\n",
       "      href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css' \n",
       "      rel='stylesheet' />\n",
       "\n",
       "<style type='text/css'>\n",
       "    body { margin:0; padding:0; }\n",
       "    .map { position: absolute; top:0; bottom:0; width:100%; }\n",
       "    .legend {\n",
       "        background-color: white;\n",
       "        color: #6e6e6e;\n",
       "        border-radius: 3px;\n",
       "        bottom: 10px;\n",
       "        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.10);\n",
       "        font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n",
       "        padding: 0;\n",
       "        position: absolute;\n",
       "        right: 10px;\n",
       "        z-index: 1;\n",
       "        min-width: 100px;\n",
       "    }\n",
       "   .legend.horizontal {bottom: 10px; text-align: left;}\n",
       "\n",
       "    /* legend header */\n",
       "    .legend .legend-header { border-radius: 3px 3px 0 0; background: white; }\n",
       "    .legend .legend-title {\n",
       "        padding: 6px 12px 6px 12px;\n",
       "        text-shadow: 0 0 2px white;\n",
       "        text-transform: capitalize;\n",
       "        text-align: center;\n",
       "        font-weight: bold !important;\n",
       "        font-size: 14px;\n",
       "        font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n",
       "        max-width: 160px;\n",
       "    }\n",
       "    .legend-title {padding: 6px 12px 6px 12px; text-shadow: 0 0 2px #FFF; text-transform: capitalize; text-align: center; max-width: 160px; font-size: 0.9em; font-weight: bold;}\n",
       "    .legend.horizontal .legend-title {text-align: left;}\n",
       "\n",
       "    /* legend items */\n",
       "    .legend-content {margin: 6px 12px 6px 12px; overflow: hidden; padding: 0; float: left; list-style: none; font-size: 0.8em;}\n",
       "    .legend.vertical .legend-item {white-space: nowrap;}\n",
       "    .legend-value {display: inline-block; line-height: 18px; vertical-align: top;}\n",
       "    .legend.horizontal ul.legend-content li.legend-item .legend-value,\n",
       "    .legend.horizontal ul.legend-content li.legend-item {display: inline-block; float: left; width: 30px; margin-bottom: 0; text-align: center; height: 30px;}\n",
       "\n",
       "    /* legend key styles */\n",
       "    .legend-key {display: inline-block; height: 10px;}\n",
       "    .legend-key.default, .legend-key.square {border-radius: 0;}\n",
       "    .legend-key.circle {border-radius: 50%;}\n",
       "    .legend-key.rounded-square {border-radius: 20%;}\n",
       "    .legend.vertical .legend-key {width: 10px; margin-right: 5px; margin-left: 1px;}\n",
       "    .legend.horizontal .legend-key {width: 30px; margin-right: 0; margin-top: 1px; float: left;}\n",
       "    .legend.horizontal .legend-key.square, .legend.horizontal .legend-key.rounded-square, .legend.horizontal .legend-key.circle {margin-left: 10px; width: 10px;}\n",
       "    .legend.horizontal .legend-key.line {margin-left: 5px;}\n",
       "    .legend.horizontal .legend-key.line, .legend.vertical .legend-key.line {border-radius: 10%; width: 20px; height: 3px; margin-bottom: 2px;}\n",
       "\n",
       "    /* gradient bar alignment */\n",
       "    .gradient-bar {margin: 6px 12px 6px 12px;}\n",
       "    .legend.horizontal .gradient-bar {width: 88%; height: 10px;}\n",
       "    .legend.vertical .gradient-bar {width: 10px; min-height: 50px; position: absolute; bottom: 4px;}\n",
       "\n",
       "    /* contiguous vertical bars (discrete) */\n",
       "    .legend.vertical.contig .legend-key {height: 15px; width: 10px;}\n",
       "    .legend.vertical.contig li.legend-item {height: 15px;}\n",
       "    .legend.vertical.contig {padding-bottom: 6px;}\n",
       "\n",
       "</style>\n",
       "\n",
       "</head>\n",
       "<body>\n",
       "\n",
       "<div id='map' class='map'></div>\n",
       "\n",
       "<script type='text/javascript'>\n",
       "\n",
       "var legendHeader;\n",
       "\n",
       "function calcColorLegend(myColorStops, title) {\n",
       "\n",
       "    // create legend\n",
       "    var legend = document.createElement('div');\n",
       "    if ('square' === 'contiguous-bar') {\n",
       "        legend.className = 'legend vertical contig';\n",
       "    }\n",
       "    else {\n",
       "        legend.className = 'legend vertical';\n",
       "    }\n",
       "\n",
       "    legend.id = 'legend';\n",
       "    document.body.appendChild(legend);\n",
       "\n",
       "    // add legend header and content elements\n",
       "    var mytitle = document.createElement('div'),\n",
       "        legendContent = document.createElement('ul');\n",
       "    legendHeader = document.createElement('div');\n",
       "    mytitle.textContent = title;\n",
       "    mytitle.className = 'legend-title'\n",
       "    legendHeader.className = 'legend-header'\n",
       "    legendContent.className = 'legend-content'\n",
       "    legendHeader.appendChild(mytitle);\n",
       "    legend.appendChild(legendHeader);\n",
       "    legend.appendChild(legendContent);\n",
       "\n",
       "    if (false === true) {\n",
       "        var gradientText = 'linear-gradient(to right, ';\n",
       "        var gradient = document.createElement('div');\n",
       "        gradient.className = 'gradient-bar';\n",
       "        legend.appendChild(gradient);\n",
       "    }\n",
       "\n",
       "    // calculate a legend entries on a Mapbox GL Style Spec property function stops array\n",
       "    for (p = 0; p < myColorStops.length; p++) {\n",
       "        if (!!document.getElementById('legend-points-value-' + p)) {\n",
       "            //update the legend if it already exists\n",
       "            document.getElementById('legend-points-value-' + p).textContent = myColorStops[p][0];\n",
       "            document.getElementById('legend-points-id-' + p).style.backgroundColor = myColorStops[p][1];\n",
       "        }\n",
       "        else {\n",
       "            // create the legend if it doesn't yet exist\n",
       "            var item = document.createElement('li');\n",
       "            item.className = 'legend-item';\n",
       "\n",
       "            var key = document.createElement('span');\n",
       "            key.className = 'legend-key square';\n",
       "            key.id = 'legend-points-id-' + p;\n",
       "            key.style.backgroundColor = myColorStops[p][1];   \n",
       "\n",
       "            var value = document.createElement('span');\n",
       "            value.className = 'legend-value';\n",
       "            value.id = 'legend-points-value-' + p;\n",
       "\n",
       "            item.appendChild(key);\n",
       "            item.appendChild(value);\n",
       "            legendContent.appendChild(item);\n",
       "            \n",
       "            data = document.getElementById('legend-points-value-' + p)\n",
       "\n",
       "            // round number values in legend if precision defined\n",
       "            if ((typeof(myColorStops[p][0]) == 'number') && (typeof(null) == 'number')) {\n",
       "                data.textContent = myColorStops[p][0].toFixed(null);\n",
       "            }\n",
       "            else {\n",
       "                data.textContent = myColorStops[p][0];\n",
       "            }\n",
       "\n",
       "            // add color stop to gradient list\n",
       "            if (false === true) {\n",
       "                if (p < myColorStops.length - 1) {\n",
       "                    gradientText = gradientText + myColorStops[p][1] + ', ';\n",
       "                }\n",
       "                else {\n",
       "                    gradientText = gradientText + myColorStops[p][1] + ')';\n",
       "                }\n",
       "                if ('vertical' === 'vertical') {\n",
       "                    gradientText = gradientText.replace('to right', 'to bottom');\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "\n",
       "    if (false === true) {\n",
       "        // convert to gradient scale appearance\n",
       "        gradient.style.background = gradientText;\n",
       "\n",
       "        // hide legend keys generated above\n",
       "        var keys = document.getElementsByClassName('legend-key');\n",
       "        for (var i=0; i < keys.length; i++) {\n",
       "            keys[i].style.visibility = 'hidden';\n",
       "        }\n",
       "\n",
       "        if ('vertical' === 'vertical') {\n",
       "            gradient.style.height = (legendContent.offsetHeight - 6) + 'px';\n",
       "        }\n",
       "    }\n",
       "\n",
       "    // add class for styling bordered legend keys\n",
       "    if (true) {\n",
       "        var keys = document.getElementsByClassName('legend-key');\n",
       "        for (var i=0; i < keys.length; i++) {\n",
       "            if (keys[i]) {\n",
       "                keys[i].classList.add('bordered');\n",
       "            }\n",
       "        }\n",
       "        var gradientBars = document.getElementsByClassName('gradient-bar');\n",
       "        for (var i=0; i < keys.length; i++) {\n",
       "            if (gradientBars[i]) {\n",
       "                gradientBars[i].classList.add('bordered');\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "\n",
       "    // update right-margin for compact Mapbox attribution based on calculated legend width\n",
       "    var attribMargin = legend.offsetWidth + 15;\n",
       "    document.getElementsByClassName('mapboxgl-ctrl-attrib')[0].style.marginRight =  attribMargin.toString() + 'px';\n",
       "\n",
       "}\n",
       "\n",
       "\n",
       "function generateInterpolateExpression(propertyValue, stops) {\n",
       "    var expression;\n",
       "    if (propertyValue == 'zoom') {\n",
       "        expression = ['interpolate', ['exponential', 1.2], ['zoom']]\n",
       "    }\n",
       "    else if (propertyValue == 'heatmap-density') {\n",
       "        expression = ['interpolate', ['linear'], ['heatmap-density']]\n",
       "    }\n",
       "    else {\n",
       "        expression = ['interpolate', ['linear'], ['get', propertyValue]]\n",
       "    }\n",
       "\n",
       "    for (var i=0; i<stops.length; i++) {\n",
       "        expression.push(stops[i][0], stops[i][1])\n",
       "    }\n",
       "    return expression\n",
       "}\n",
       "\n",
       "\n",
       "function generateMatchExpression(propertyValue, stops, defaultValue) {\n",
       "    var expression;\n",
       "    expression = ['match', ['get', propertyValue]]\n",
       "    for (var i=0; i<stops.length; i++) {\n",
       "        expression.push(stops[i][0], stops[i][1])\n",
       "    }\n",
       "    expression.push(defaultValue)\n",
       "    \n",
       "    return expression\n",
       "}\n",
       "\n",
       "\n",
       "function generatePropertyExpression(expressionType, propertyValue, stops, defaultValue) {\n",
       "    var expression;\n",
       "    if (expressionType == 'match') {\n",
       "        expression = generateMatchExpression(propertyValue, stops, defaultValue)\n",
       "    }\n",
       "    else if (propertyValue == 'identity') {\n",
       "        expression = ['get', propertyValue]\n",
       "    }\n",
       "    else {\n",
       "        expression = generateInterpolateExpression(propertyValue, stops)\n",
       "    }\n",
       "\n",
       "    return expression\n",
       "}\n",
       "\n",
       "</script>\n",
       "\n",
       "<!-- main map creation code, extended by mapboxgl/templates/raster.html -->\n",
       "<script type='text/javascript'>\n",
       "\n",
       "    mapboxgl.accessToken = 'pk.eyJ1IjoidmluY2VudHNhcmFnbyIsImEiOiJjamxwa3JkaWkwZ3BjM3dudmZmazQwYjI2In0.eUzks_hqH-QVIlnXUKmKsA';\n",
       "\n",
       "    var transformRequest = function(url, resourceType) {\n",
       "        const isMapboxRequest = url.slice(8, 22) === 'api.mapbox.com' ||\n",
       "          url.slice(10, 26) === 'tiles.mapbox.com';\n",
       "      \n",
       "        return {\n",
       "          url: isMapboxRequest ? url.replace('?', '?pluginName=PythonMapboxgl&') : url\n",
       "        }\n",
       "    };\n",
       "\n",
       "    var map = new mapboxgl.Map({\n",
       "        container: 'map',\n",
       "        attributionControl: false,\n",
       "        style: 'mapbox://styles/mapbox/light-v10?optimize=true',\n",
       "        center: [9.99835, -0.0031079999999999997],\n",
       "        zoom: 10,\n",
       "        pitch: 0,\n",
       "        bearing: 0,\n",
       "        scrollZoom: true,\n",
       "        touchZoom: true,\n",
       "        doubleClickZoom: true,\n",
       "        boxZoom: true,\n",
       "        preserveDrawingBuffer: false,\n",
       "        transformRequest: transformRequest\n",
       "    });\n",
       "\n",
       "    \n",
       "    \n",
       "        map.addControl(new mapboxgl.AttributionControl({ compact: true }));\n",
       "\n",
       "    \n",
       "\n",
       "    \n",
       "\n",
       "        map.addControl(new mapboxgl.NavigationControl());\n",
       "\n",
       "    \n",
       "\n",
       "    \n",
       "\n",
       "    \n",
       "\n",
       "    map.on('style.load', function() {\n",
       "      console.log('Yoooooo');\n",
       "        let params = {\n",
       "            'type': 'raster',\n",
       "            'tiles': [\n",
       "                 'http://127.0.0.1:8000/tiles/{z}/{x}/{y}.png?url=s3%3A%2F%2Fcumulus-map-internal%2Fproducts%2FAFLVIS2-CHM%2FLVIS2_Gabon2016_0220_R1808_038024_chm.tif&rescale=0%2C70&color_map=schwarzwald'\n",
       "            ],\n",
       "            'tileSize': 256,\n",
       "            'minzoom': 8,\n",
       "            'maxzoom': 15\n",
       "        }\n",
       "        if ([9.79035, -0.171108, 10.20635, 0.164892] !== undefined) params.bounds = [9.79035, -0.171108, 10.20635, 0.164892];\n",
       "\n",
       "        map.addSource('raster-tiles', params);\n",
       "\n",
       "        map.addLayer({\n",
       "            'id': 'raster-tiles',\n",
       "            'type': 'raster',\n",
       "            'source': 'raster-tiles'\n",
       "        }, '' );\n",
       "\n",
       "    });\n",
       "\n",
       "\n",
       "\n",
       "</script>\n",
       "\n",
       "<!-- add capability to export map or legend to image file -->\n",
       "\n",
       "\n",
       "</body>\n",
       "</html>\" style=\"width: 100%; height: 800px;\"></iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bbox = meta[\"bounds\"][\"value\"]\n",
    "lat = (bbox[3] - bbox[1]) / 2 + bbox[1]\n",
    "lng = (bbox[2] - bbox[0]) / 2 + bbox[0]\n",
    "\n",
    "query_params = dict(\n",
    "    url=LVIS_file,\n",
    "    rescale=\"0,70\",\n",
    "    color_map=\"schwarzwald\"\n",
    ")\n",
    "\n",
    "#Because the data is of `float` type we need to rescale the data between 0 and 255\n",
    "# `rescale=\"-10,200\"`: tell the tiler to rescale the data from -10 and 200 to 0 and 255. \n",
    "#\n",
    "# `color_map=\"schwarzwald\"`: The tiler can also apply a color map on the fly using the `color_map` option\n",
    "\n",
    "qs = urllib.parse.urlencode(query_params)\n",
    "\n",
    "tiles_url = f\"{maap_endpoint}/tiles/{{z}}/{{x}}/{{y}}.png?{qs}\"\n",
    "viz = RasterTilesViz(\n",
    "    tiles_url,\n",
    "    height='800px',\n",
    "    zoom=10,\n",
    "    access_token=token,\n",
    "    tiles_size=256,\n",
    "    tiles_bounds=bbox,\n",
    "    center=(lng, lat),\n",
    "    tiles_minzoom=8,\n",
    "    tiles_maxzoom=15,\n",
    ")\n",
    "\n",
    "viz.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
